//
// Created by Luhang on 2024/1/11/011.
//
#include <mutex>
#include <thread>
#include <iostream>
#include <memory>

#ifndef INC_0704_SMARTPTR_H
#define INC_0704_SMARTPTR_H

namespace Lu{
    template<class T>
    class auto_ptr{
    public:
        auto_ptr(T* ptr)
            :_ptr(ptr){}

        ~auto_ptr(){
            if (_ptr){
                std::cout << "delete:" << _ptr << std::endl;
                delete _ptr;
            }
        }

        auto_ptr(auto_ptr<T>& ap)
            :_ptr(ap._ptr){
            ap._ptr = nullptr;
        }

        T& operator*(){
            return *_ptr;
        }

        T* operator->(){
            return _ptr;
        }

    private:
        T* _ptr;
    };

    void testAuto(){
        auto_ptr<int> ap1(new int(1));
        auto_ptr<int> ap2(ap1);

        //*ap1 = 10;
        *ap2 = 5;
    }

    template<class T>
    class unique_ptr{
    public:
        unique_ptr(T* ptr)
            :_ptr(ptr){}

        ~unique_ptr(){
            if (_ptr){
                std::cout << "delete:" << _ptr << std::endl;
            }
        }

        T& operator*(){
            return *_ptr;
        }

        T* operator->(){
            return _ptr;
        }

        unique_ptr(const unique_ptr<T>& up) = delete;
        unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;

    private:
        T* _ptr;
    };

    void testUnique(){
        unique_ptr<int> up1(new int (1));
        //unique_ptr<int> up2(up1);
    }

/*    template<class T>
    class shared_ptr{
    public:
        shared_ptr(T* ptr)
            :_ptr(ptr)
            ,_pCount(new int(1)){}

        ~shared_ptr(){
            if (--(*_pCount) == 0){
                if (_ptr){
                    std::cout << "delete:" << _ptr << std::endl;
                    delete _ptr;
                }
                delete _pCount;
            }
        }

        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            ,_pCount(sp._pCount){
            ++(*_pCount);
        }

        shared_ptr<T>& operator=(const shared_ptr<T>& sp){
            if (_ptr != sp._ptr){
                if (--(*_pCount) == 0){
                    std::cout << "delete:" << _ptr << std::endl;
                    delete _ptr;
                    delete _pCount;
                }
                _ptr = sp._ptr;
                _pCount = sp._pCount;
                ++(*_pCount);
            }
            return *this;
        }

        int useCount(){
            return *_pCount;
        }

        T& operator*(){
            return *_ptr;
        }

        T* operator->(){
            return _ptr;
        }

    private:
        T* _ptr;
        int* _pCount;
    };

    void testShared(){
        shared_ptr<int> sp1(new int(1));
        shared_ptr<int> sp2(sp1);
        shared_ptr<int> sp3(sp1);

        shared_ptr<int> sp4(new int(10));

        sp1 = sp4;
    }*/

    //线程安全
    template<class T>
    class shared_ptr{
    public:
        shared_ptr(T* ptr)
            :_ptr(ptr)
            ,_pCount(new int(1))
            ,_pMutex(new mutex){}

        ~shared_ptr(){
            Release();
        }

        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            ,_pCount(sp._pCount)
            ,_pMutex(sp._pMutex){
            AddCount();
        }

        shared_ptr<T>& operator=(const shared_ptr<T>& sp){
            if (_ptr != sp._ptr){
                Release();
                _ptr = sp._ptr;
                _pCount = sp._pCount;
                _pMutex = sp._pMutex;
                AddCount();
            }
            return *this;
        }

        T& operator*(){
            return *_ptr;
        }

        T* operator->(){
            return _ptr;
        }

        T* get(){
            return _ptr;
        }

        int useCount(){
            return *_pCount;
        }

        void AddCount(){
            _pMutex->lock();
            ++(*_pCount);
            _pMutex->unlock();
        }

        void Release(){
            _pMutex->lock();
            bool flag = false;
            if (--(*_pCount) == 0){
                if (_ptr){
                    std::cout << "delete:" << _ptr << std::endl;
                    delete _ptr;
                }
                delete _pCount;
                flag = true;
            }
            _pMutex->unlock();
            if (flag)
                delete _pMutex;
        }

    private:
        T* _ptr;
        int* _pCount;
        mutex* _pMutex;
    };

    struct Date{
        int _year = 0;
        int _month = 0;
        int _day = 0;

        ~Date()
        {}
    };

    void SharedPtrFunc(Lu::shared_ptr<Date>& sp, size_t n, mutex& mtx){
        for (int i = 0; i < n; ++i) {
            Lu::shared_ptr<Date> copy(sp);
        }
    }

    void testSharedSafe(){
        Lu::shared_ptr<Date> pd(new Date);
        const size_t n = 100000;
        mutex m;
        thread t1(SharedPtrFunc, ref(pd), n, ref(m));
        thread t2(SharedPtrFunc, ref(pd), n, ref(m));
        t1.join();
        t2.join();
        std::cout << pd.useCount() << std::endl;
    }

    void testSharedDeleter(){
        std::shared_ptr<Date> sp(new Date[10], [](Date* ptr){delete[] ptr;});
    }
}

#endif //INC_0704_SMARTPTR_H
